home *** CD-ROM | disk | FTP | other *** search
/ Just Call Me Internet / Just Call Me Internet.iso / prog / atari / m2 / cat3src / cat / messages.i < prev    next >
Text File  |  1997-10-26  |  59KB  |  1,870 lines

  1. IMPLEMENTATION MODULE Messages;
  2.  
  3. FROM SYSTEM     IMPORT  TSIZE, ADDRESS, ADR, CALLSYS, CADR, BYTE, ASSEMBLER;
  4.  
  5.  
  6. (* MM2-Module *)
  7. IMPORT Block, Strings, StrConv, GrafBase, BinOps, MOSGlobals,
  8.        Keyboard;
  9. FROM Keyboard  IMPORT SpecialCode;
  10. FROM Storage    IMPORT ALLOCATE, DEALLOCATE;
  11.  
  12.  
  13. (* Magic-Module *)
  14. IMPORT MagicAES, MagicVDI, MagicDOS, MagicFSM, mtTextfiles, mtAlerts, mtAppl,
  15.        mtUtils, mtDials, mtPopups, MagicXBIOS;
  16. FROM MagicSys   IMPORT Bit0, Bit1, Bit2, Bit3, Bit4, Bit5, Bit6, Bit7,
  17.                        Bit8, Bit9, Bit10, Bit11, Bit12, Bit13, Bit14, Bit15;
  18.  
  19.  
  20. (* CAT-Module *)
  21. IMPORT ARCStarter, CatFiles, CatTypes, MTE, MTEdit2, 
  22.        CatEdit, FontSelect, WdwManager, VDIUtil, ConfVars,
  23.        CatGlobal, EditTypes, MausTauschrsc, grinTools, ListHelp,
  24.        grin, data, dataSys, QuickSort, Varnames, Infofiles, RectFuncs,
  25.        GroupSelect, WinDials, Protokoll;
  26.  
  27. FROM CatGlobal   IMPORT OpenName;
  28. FROM MTPaths     IMPORT MessagePath, DataPath, ExportPath, ImportPath, ARCName;
  29. IMPORT ConvertDate;
  30. FROM UserInformation IMPORT UserBLK, batchProcess;
  31. FROM Void        IMPORT v;
  32.  
  33. IMPORT MsgWindow;
  34.  
  35. CONST   emptyStr = 0C;
  36.         msgFileName = 'msg'+0C;
  37.         msgInfoName = 'msginfo.dat'+0C;
  38.  
  39.         (* Magics fr Header *)
  40.         msgCatMagic     = 4341544DH;  (* "CATM"                    *)
  41.         msgVersion      = 2;          (* Versionsnummer der MsgManager.i *)
  42.  
  43.         (* msgVersionMagic = 0150H;      (* CAT 2.0 bis 2.04 *) *)
  44.  
  45.         msgVersionMagic = 0160H;      (* Versionsmagic                   *)
  46.  
  47. (*=======================================================================*)
  48. (* Funktionen und Typen fr das Editorfenster                            *)
  49. (*=======================================================================*)
  50.  
  51. TYPE
  52.      boxHandler   = POINTER TO boxHandleRec;
  53.      
  54.      boxHandleRec = RECORD
  55.                       wdw     : INTEGER;
  56.                       number  : INTEGER;        (* Messagenummer! *)
  57.                       r       : GrafBase.Rectangle;
  58.                       infoStr : ARRAY [0..255] OF CHAR;
  59.                       tree    : mtUtils.tObjcTree;
  60.                       dontUpdate : BOOLEAN;
  61.                       
  62.                       next    : boxHandler;
  63.                     END;
  64.  
  65.  
  66. VAR wdw : INTEGER;
  67.     boxList : boxHandler;
  68.  
  69. (* Messagenummer-Verwaltung: Es wird in dem Set festgehalten, welche Nummern 
  70.  * schon vergeben wurden und welche nicht. FindNumber gibt die niedrigste freie
  71.  * Nummer zurck, ClearNumber l”scht die bergebene Nummer aus dem Set
  72.  *)
  73.  
  74. PROCEDURE FindNumber (min : INTEGER) : INTEGER;
  75.   VAR i : INTEGER;
  76. BEGIN
  77.   min := BinOps.HigherInt (min, 1);
  78.   FOR i := min TO 999 DO
  79.     IF ~(i IN usedNumbers) THEN INCL (usedNumbers, i); RETURN i; END;
  80.   END;
  81.   RETURN 1000;
  82. END FindNumber;
  83.  
  84. PROCEDURE ClearNumber (num : INTEGER);
  85. BEGIN
  86.   EXCL (usedNumbers, num);
  87. END ClearNumber;
  88.  
  89. PROCEDURE FindMessage (number : INTEGER): INTEGER; 
  90.   VAR i : INTEGER;
  91. BEGIN
  92.   FOR i := 0 TO messages - 1 DO
  93.     IF msgArray^[i].number = number
  94.     THEN RETURN i
  95.     END;
  96.   END;
  97.   RETURN -1;
  98. END FindMessage;
  99.  
  100. (* Ein paar Hilfsroutinen *)
  101.  
  102. PROCEDURE Number2Name (number : CARDINAL; VAR str : ARRAY OF CHAR); 
  103. (* šbergeben wird die Nummer, gibt zurck 'MSGxxx'
  104.  * Die Extension muž dann noch angeh„ngt werden.
  105.  *)
  106. BEGIN
  107.   Strings.Assign (msgFileName, str, v.bool);
  108.   Strings.Append (StrConv.NumToStr (number, 10, 3, '0'), str, v.bool);
  109. END Number2Name;
  110.  
  111. PROCEDURE MakeMyDate (date, time: CARDINAL; VAR myDate: LONGCARD);
  112.   (* Erzeugt ein Datum fr IDs,. 24 Bit lang und damit 
  113.    * 5 Zeichen im 36er System.
  114.    * Das Format sieht wie folgt aus:
  115.    * Bit  0..5:  Minute (6 Bits)
  116.    * Bit  6..11: Stunde (5 Bits)
  117.    * Bit 12..16: Tag    (5 Bits)
  118.    * Bit 17..20: Monat  (4 Bits)
  119.    * Bit 21..24: (Jahr seit 1980) MOD 16 (4 Bits)
  120.    *)
  121.   VAR j, m, d, s, min : LONGCARD;
  122. BEGIN
  123.   d := date MOD 32; (* Tag herausholen *)
  124.   date := date DIV 32;
  125.   m := date MOD 16; (* Monat herausholen *)
  126.   date := date DIV 16;
  127.   j := date MOD 16; (* Jahr MOD 16 herausholen *)
  128.   time := time DIV 32;  (* Sekunden wegrechnen *)
  129.   min := time MOD 64;
  130.   time := time DIV 64;
  131.   s := time MOD 32;     (* Sollte eigentlich gar nix mehr wegzurechnen haben *)
  132.   (* Nun das neue Datum einpacken *)
  133.   myDate := (((((((j * 16) + m) * 32) + d) * 32) + s) * 64) + min;
  134. END MakeMyDate;
  135.  
  136. PROCEDURE MakeMausId (msg: msgInfo; VAR str : ARRAY OF CHAR); 
  137. (* Erzeugt eine ID, wie sie an die Maus geschickt wird. 
  138.  * Format: 
  139.  * CM###ddddd, ### ist die interne Messagenummer, 
  140.  * ddddd ist das Datum und die Zeit im 36er System
  141.  *)
  142.  VAR myDate : LONGCARD;
  143. BEGIN
  144.   Strings.Assign ('CM', str, v.bool);
  145.   Strings.Append (StrConv.NumToStr (msg.number, 10, 3, '0'), str, v.bool);
  146.   (* Nun wird aus den GEMDOS-Daten ein eigenes Datum erzeugt, da die Maus 
  147.    * nur IDs mit 10 Stellen annimmt, ich aber mindestens 13 br„uchte :-((
  148.    * Daher habe ich ein eigenes Format eingebaut, das nicht alle
  149.    * Informationen enth„lt, aber genau genug ist und 24 Bit belegt.
  150.    *)
  151.   MakeMyDate (msg.cDate, msg.cTime, myDate);
  152.   Strings.Append (StrConv.LNumToStr (myDate, 36, 5, '0'), str, v.bool);
  153. END MakeMausId;
  154.  
  155. PROCEDURE FileSize (REF path, name : ARRAY OF CHAR; VAR date, time: CARDINAL) : LONGCARD;
  156.   VAR fn : CatTypes.String255;
  157. BEGIN
  158.   Strings.Assign(path, fn, v.bool);
  159.   Strings.Append(name, fn, v.bool);
  160.   RETURN CatFiles.FileSizeAndDate (fn, v.bool, date, time);
  161. END FileSize;
  162.  
  163. PROCEDURE FixDate (idx: INTEGER);
  164.   VAR tmpName : CatTypes.String255;
  165. BEGIN
  166.   (* Noch altes Format, Dateidatum der Messagedatei nehmen *)
  167.   Number2Name (msgArray^[idx].number, tmpName);
  168.   Strings.Append (CatTypes.textExt, tmpName, v.bool);
  169.   v.lint := FileSize (MessagePath, tmpName, 
  170.                       msgArray^[idx].cDate, msgArray^[idx].cTime);
  171. END FixDate;
  172.  
  173. PROCEDURE hasNumbers (REF internalId : ARRAY OF CHAR): BOOLEAN;
  174.   CONST nums = CatTypes.charSet {'0'..'9'};
  175. BEGIN
  176.   RETURN (internalId[2] IN nums) & 
  177.          (internalId[3] IN nums) &
  178.          (internalId[4] IN nums);
  179. END hasNumbers;
  180.  
  181. PROCEDURE isMessage (REF internalId : ARRAY OF CHAR): BOOLEAN;
  182.   VAR  msgName   : CatTypes.String127;
  183. BEGIN
  184.   msgName := msgFileName;
  185.   RETURN ((internalId[0] = msgName[0]) 
  186.         & (internalId[1] = msgName[1]) 
  187.         & (internalId[2] = msgName[2])) 
  188.     OR   (hasNumbers (internalId) 
  189.         & (internalId[0] = 'C')
  190.         & (internalId[1] = 'M'));
  191. END isMessage;
  192.  
  193. PROCEDURE GetMessIdx (REF internalId : ARRAY OF CHAR): INTEGER;
  194.   VAR number    : INTEGER;
  195.       pos       : CARDINAL;
  196.       numStr    : ARRAY [0..7] OF CHAR;
  197.       long      : BOOLEAN;
  198.       idx       : INTEGER;
  199.       cLong,
  200.       xLong     : LONGCARD;
  201.       msg       : msgInfo;
  202. BEGIN
  203.   long := FALSE;
  204.   IF hasNumbers (internalId)
  205.   THEN
  206.     pos := 0;
  207.     Strings.Copy (internalId, 2, 3, numStr, v.bool);
  208.     numStr [3] := '';
  209.     number := StrConv.StrToCard (numStr, pos, v.bool);
  210.     long := TRUE;
  211.   ELSE
  212.     pos := 3;
  213.     number := StrConv.StrToInt (internalId, pos, v.bool);
  214.   END;
  215.   idx := FindMessage (number);
  216.   IF long & (idx >= 0)
  217.   THEN
  218.     (* Nun bei langem Format auch noch Datum und Zeit prfen *)
  219.     pos := 0;
  220.     Strings.Copy (internalId, 5, 5, numStr, v.bool);
  221.     xLong := StrConv.StrToLNum (numStr, 36, pos, v.bool);
  222.     msg := msgArray^[idx];
  223.     MakeMyDate (msg.cDate, msg.cTime, cLong);
  224.     IF (xLong = cLong) 
  225.     THEN
  226.       RETURN idx
  227.     ELSE
  228.       RETURN -1
  229.     END;
  230.   ELSE 
  231.     RETURN idx;
  232.   END;
  233. END GetMessIdx;
  234.  
  235. (*=========================================================================*)
  236.  
  237. PROCEDURE MakeNewMsgArray (force : BOOLEAN; new : CARDINAL) : BOOLEAN;
  238. (* Alloziert ein neues Messagearray und kopiert das alte hinein.
  239.  * FALSE: Nicht genug Speicher!
  240.  *)
  241.  VAR i :  INTEGER;
  242.      newMax : CARDINAL;
  243.      newArray : msgArrayPtr;
  244. BEGIN
  245.   IF (messages = maxMess - 1) OR force
  246.   THEN
  247.     IF force
  248.     THEN
  249.       newMax := new + 20;
  250.     ELSE
  251.       newMax := maxMess + 20;
  252.     END;
  253.     ALLOCATE (newArray, LONG(newMax) * TSIZE (msgInfo));
  254.     IF newArray = NIL THEN RETURN FALSE END;
  255.     Block.Clear (newArray, LONG(newMax)*TSIZE(msgInfo));
  256.     IF msgArray # NIL 
  257.     THEN
  258.       FOR i := 0 TO INTEGER(maxMess) - 1 DO newArray^[i] := msgArray^[i] END;
  259.       DEALLOCATE (msgArray, 0);
  260.     END;
  261.     msgArray := newArray;
  262.     FOR i := INTEGER(maxMess) TO INTEGER (newMax) - 1 DO 
  263.       msgArray^[i].hdrRead := FALSE;
  264.     END;
  265.     maxMess := newMax; 
  266.     MsgWindow.MsgSetList (msgArray, FALSE);
  267.     (* !!!!  msgWindow.list := msgArray; *)
  268.   END;
  269.   RETURN TRUE;
  270. END MakeNewMsgArray;
  271.  
  272. (* Array I/O *)
  273. PROCEDURE ReadMessageInfo();
  274. (* Diese Prozedur liest das Infoarray von der
  275.  * Platte und z„hlt auch am Anfang die Messages
  276.  *)
  277.  VAR    msgHdl  : INTEGER;
  278.         size    : LONGCARD;
  279.         mess    : CARDINAL;
  280.         shortArray : diskArrayPtr;
  281.         i       : INTEGER;
  282.         j       : lineType;
  283.         dbHdr   : dataSys.FileHeaderType;
  284.         readMessages : BOOLEAN;
  285. BEGIN
  286.   (* Datei ”ffnen *)
  287.   mess := 0;
  288.   msgHdl := CatFiles.OpenFile (MessagePath, msgInfoName, CatFiles.readFile);
  289.   IF msgHdl = -33       (* File not found *)
  290.   THEN
  291.     messages := 0;
  292.     v.bool := MakeNewMsgArray (TRUE, messages);
  293.     readMessages := FALSE;
  294.   ELSE
  295.     IF msgHdl < 0 THEN CatFiles.ErrorAlert (msgHdl); RETURN END;
  296.     CatFiles.Seek (0, msgHdl, CatFiles.end);
  297.     size := CatFiles.FilePos (msgHdl);
  298.     IF size < dataSys.dbHeaderLength
  299.     THEN
  300.       messages := 0;
  301.       v.bool := MakeNewMsgArray (TRUE, mess);
  302.       readMessages := FALSE;
  303.     ELSE
  304.       mess := SHORT((size - dataSys.dbHeaderLength) DIV TSIZE (shortInfo));
  305.       IF mess > 0
  306.       THEN
  307.         ALLOCATE (shortArray, size - dataSys.dbHeaderLength);
  308.         IF shortArray = NIL THEN CatFiles.CloseFile (msgHdl); RETURN END;
  309.         IF ~ MakeNewMsgArray (TRUE, mess)
  310.         THEN
  311.           DEALLOCATE (shortArray, 0);
  312.           CatFiles.CloseFile (msgHdl);
  313.           RETURN
  314.         END;
  315.       ELSE
  316.         CatFiles.CloseFile (msgHdl);
  317.         v.bool := MakeNewMsgArray (TRUE, mess);
  318.       END;
  319.       readMessages := mess > 0;
  320.     END;
  321.   END;
  322.   IF readMessages
  323.   THEN
  324.  
  325.     (* Jetzt erst mal Header einlesen *)
  326.     CatFiles.Seek (0, msgHdl, CatFiles.start);
  327.     CatFiles.ReadMuch (dataSys.dbHeaderLength, msgHdl, ADR(dbHdr));
  328.     IF CatFiles.FileError # CatFiles.NoError
  329.     THEN
  330.       CatFiles.ErrorAlert (CatFiles.FileError);
  331.       CatFiles.CloseFile (msgHdl);
  332.       DEALLOCATE (shortArray, 0);
  333.       RETURN
  334.     END;
  335.  
  336.     (* Jetzt berprfen des Headers *)
  337.     IF (dbHdr.CatMagic # msgCatMagic)
  338.     OR (dbHdr.Version  # msgVersion)
  339.     OR (dbHdr.VersionMagic # msgVersionMagic)
  340.     THEN
  341.       MTE.info (MTE.oldMsgVersion);
  342.       CatFiles.CloseFile (msgHdl);
  343.       DEALLOCATE (shortArray, 0);
  344.       RETURN
  345.     END;
  346.  
  347.     (* An den Start der Daten seeken *)
  348.     CatFiles.Seek (TSIZE (dataSys.FileHeaderType), msgHdl, CatFiles.start);
  349.  
  350.     (* Alles einlesen in shortArray*)
  351.     CatFiles.ReadMuch (size - dataSys.dbHeaderLength, msgHdl, shortArray);
  352.     IF CatFiles.FileError # CatFiles.NoError
  353.     THEN
  354.       CatFiles.ErrorAlert (CatFiles.FileError);
  355.       CatFiles.CloseFile (msgHdl);
  356.       DEALLOCATE (shortArray, 0);
  357.       RETURN
  358.     END;
  359.     (* und File schliežen *)   
  360.     CatFiles.CloseFile (msgHdl);
  361.     
  362.     (* alten Speicher freigeben *)
  363.     FOR i := 0 TO messages-1 DO 
  364.       FOR j := dateL TO rNameL DO
  365.         IF msgArray^[i].strings[j] # NIL 
  366.         THEN
  367.           DEALLOCATE (msgArray^[i].strings[j], 0);
  368.         END;
  369.       END;
  370.     END;
  371.  
  372.     (* Messageinfo l”schen *)
  373.     Block.Clear (msgArray, LONG(mess)*TSIZE(msgInfo));
  374.     FOR i := 0 TO INTEGER(mess) - 1 DO 
  375.       msgArray^[i].info := shortArray^[i];
  376.       msgArray^[i].hdrRead := FALSE;
  377.       msgArray^[i].selected := FALSE;
  378.       msgArray^[i].isSend   := FALSE;
  379.       FOR j := dateL TO rNameL DO
  380.         msgArray^[i].strings[j] := NIL;
  381.       END;
  382.       IF msgArray^[i].cDate = 0
  383.       THEN
  384.         FixDate (i);
  385.       END;
  386.       INCL (usedNumbers, msgArray^[i].number); 
  387.     END;
  388.     (* shortarray freigeben *)
  389.     DEALLOCATE (shortArray, 0);
  390.     
  391.     messages := mess;
  392.     MsgWindow.MsgSetMaxPos (messages-1, TRUE);
  393.   END;
  394. END ReadMessageInfo;
  395.  
  396. PROCEDURE WriteMessageInfo(doRedrawWdw: BOOLEAN);
  397. (* Diese Prozedur schreibt das Info-Array 
  398.  * fr die Messages weg
  399.  *)
  400.   VAR shortArray : diskArrayPtr;
  401.       i          : INTEGER;
  402.       msgHdl     : INTEGER;
  403.       dbHdr      : dataSys.FileHeaderType;
  404. BEGIN
  405.   IF messages = 0 
  406.   THEN
  407.     v.bool := CatFiles.DeleteFile (MessagePath, msgInfoName);
  408.     MsgWindow.MsgCloseIfOpen();
  409.     (* !!!!
  410.     IF msgWindow.wdw >= 0
  411.     THEN
  412.       msgClose (msgWindow.wdw);
  413.     END; 
  414.     *)
  415.     Protokoll.SendPathUpdate (MessagePath);
  416.     RETURN
  417.   END;
  418.   ALLOCATE (shortArray, LONG(messages) * TSIZE (shortInfo));
  419.   IF shortArray = NIL
  420.   THEN RETURN END;
  421.   FOR i := 0 TO messages-1 DO
  422.     shortArray^[i] := msgArray^[i].info;
  423.   END;
  424.   msgHdl := CatFiles.CreateFile (MessagePath, msgInfoName);
  425.   IF msgHdl < 0 THEN 
  426.     CatFiles.ErrorAlert (msgHdl); 
  427.     DEALLOCATE (shortArray, 0);
  428.   END;
  429.   dbHdr.CatMagic := msgCatMagic;
  430.   dbHdr.Version  := msgVersion;
  431.   dbHdr.VersionMagic := msgVersionMagic;
  432.   CatFiles.WriteMuch (dataSys.dbHeaderLength, msgHdl, ADR(dbHdr));
  433.   IF CatFiles.FileError # CatFiles.NoError
  434.   THEN
  435.     CatFiles.ErrorAlert (CatFiles.FileError);
  436.     DEALLOCATE (shortArray, 0);
  437.     CatFiles.CloseFile (msgHdl);
  438.     RETURN
  439.   END;
  440.   CatFiles.WriteMuch (LONG(messages) * TSIZE (shortInfo), msgHdl, shortArray);
  441.   IF CatFiles.FileError # CatFiles.NoError
  442.   THEN
  443.     CatFiles.ErrorAlert (CatFiles.FileError);
  444.   END;
  445.   DEALLOCATE (shortArray, 0);
  446.   CatFiles.CloseFile (msgHdl);
  447.   MsgWindow.MsgSetList (msgArray, FALSE);
  448.   MsgWindow.MsgSetMaxPos (messages - 1, doRedrawWdw);
  449. END WriteMessageInfo;
  450.  
  451. PROCEDURE ReReadMessageInfo();
  452. (* Liest die MSGINFO.DAT erneut ein
  453.  *)
  454.    VAR i   : INTEGER;
  455.        j   : lineType;
  456. BEGIN
  457.   (* MSGINFO.DAT neu einlesen *)
  458.   (* alten Speicher freigeben *)
  459.   FOR i := 0 TO messages-1 DO 
  460.     FOR j := dateL TO rNameL DO
  461.       IF msgArray^[i].strings[j] # NIL 
  462.       THEN
  463.         DEALLOCATE (msgArray^[i].strings[j], 0);
  464.       END;
  465.     END;
  466.   END;
  467.   IF msgArray # NIL THEN DEALLOCATE (msgArray, 0); END;
  468.   msgArray := NIL;
  469.   messages := 0;
  470.   usedNumbers := msgNumberSet{};
  471.   ReadMessageInfo();
  472. END ReReadMessageInfo;
  473.  
  474.         (* Header-File I/O *)
  475.  
  476. PROCEDURE deleteMessage (REF internalId : ARRAY OF CHAR; killEdit: BOOLEAN;
  477.                          changeState : BOOLEAN); FORWARD;
  478.  
  479. PROCEDURE ReadHdrInfo (VAR msg : msgInfo; externalRef: BOOLEAN);
  480. (* Liest die Header-Zeilen aus der Datei MSGxxx.HDR ein
  481.  *)
  482.   VAR hdrName : CatTypes.String255;
  483.       hdrHdl  : mtTextfiles.TEXTFILE;
  484.       aLine   : CatTypes.String1023;
  485.       line    : lineType;
  486.       idx     : INTEGER;
  487. BEGIN
  488.   (* Filenamen basteln *)
  489.   Number2Name (msg.number, hdrName);
  490.   Strings.Append (CatTypes.headerExt, hdrName, v.bool);
  491.   Strings.Insert (MessagePath, 0, hdrName, v.bool);
  492.   (* File ”ffnen *)
  493.   IF mtTextfiles.OpenTextfile (hdrName, mtTextfiles.READ, 4096, hdrHdl)
  494.   THEN
  495.     (* Jetzt die einzelnen Zeilen lesen *)
  496.     FOR line := dateL TO rNameL DO 
  497.       aLine := "";
  498.       mtTextfiles.ReadLine (hdrHdl, aLine);
  499.       mtTextfiles.ReadLn (hdrHdl);
  500.       IF msg.strings[line] # NIL
  501.       THEN
  502.         DEALLOCATE (msg.strings[line], 0);
  503.       END;
  504.       ALLOCATE (msg.strings[line], LENGTH (aLine)+2);
  505.       IF msg.strings[line] = NIL 
  506.       THEN
  507.         (* Out of Memory *)
  508.         MTE.noMemAlert();
  509.         mtTextfiles.CloseTextfile (hdrHdl);
  510.         idx := FindMessage (msg.number);
  511.         IF idx >= 0 THEN msgArray^[idx] := msg END;
  512.         RETURN 
  513.       END;
  514.       Strings.Assign (aLine, msg.strings[line]^, v.bool);
  515.     END;
  516.     (* File wieder schliežen *)
  517.     mtTextfiles.CloseTextfile (hdrHdl);
  518.     msg.hdrRead := TRUE;
  519.     IF externalRef
  520.     THEN
  521.       idx := FindMessage (msg.number);
  522.       IF idx >= 0 THEN msgArray^[idx] := msg END;
  523.     END;
  524.   ELSE  
  525.     (* prfen, ob die Datei wirklich existiert. Wenn nicht, dann muž 
  526.      * die Message gel”scht werden! 
  527.      *)
  528.     Number2Name (msg.number, hdrName);
  529.     Strings.Append (CatTypes.headerExt, hdrName, v.bool);
  530.     IF FileSize (MessagePath, hdrName, v.card, v.card) = 0
  531.     THEN
  532.       (* File nicht da oder leer, weg damit! *)
  533.       Number2Name (msg.number, hdrName);
  534.       (*
  535.       deleteMessage (hdrName, TRUE, TRUE);
  536.       *)
  537.     ELSE
  538.       MTE.noMemAlert();
  539.     END;
  540.   END;
  541. END ReadHdrInfo;
  542.  
  543. PROCEDURE WriteHdrInfo (VAR msg : msgInfo);
  544. (* Schreibt die Header-Zeilen in die Datei MSGxxx.HDR
  545.  *)
  546.   VAR hdrName : CatTypes.String255;
  547.       hdrHdl  : mtTextfiles.TEXTFILE;
  548.       aLine   : CatTypes.String1023;
  549.       line    : lineType;
  550. BEGIN
  551.   (* Filenamen basteln *)
  552.   Number2Name (msg.number, hdrName);
  553.   Strings.Append (CatTypes.headerExt, hdrName, v.bool);
  554.   Strings.Insert (MessagePath, 0, hdrName, v.bool);
  555.   (* File ”ffnen *)
  556.   IF mtTextfiles.OpenTextfile (hdrName, mtTextfiles.WRITE, 4096, hdrHdl) 
  557.   THEN
  558.     (* Jetzt die einzelnen Zeilen schreiben *)
  559.     FOR line := dateL TO rNameL DO 
  560.       IF msg.strings[line] # NIL THEN
  561.         mtTextfiles.WriteLine (hdrHdl, msg.strings[line]^);
  562.       END;
  563.       mtTextfiles.WriteLn (hdrHdl);
  564.     END;
  565.     (* File wieder schliežen *)
  566.     mtTextfiles.CloseTextfile (hdrHdl);
  567.   ELSE
  568.     MTE.noMemAlert ();
  569.   END;
  570. END WriteHdrInfo;
  571.  
  572. (*=========================================================================*)
  573.  
  574. (* Verwaltung der einzelnen Editboxen *)
  575.  
  576. PROCEDURE CreateHandler (VAR bx : boxHandler) : BOOLEAN;
  577.   VAR currBx : boxHandler;
  578.       found  : BOOLEAN;
  579. BEGIN
  580.   found := FALSE;
  581.   NEW (bx);
  582.   IF bx = NIL THEN RETURN FALSE END;
  583.   IF boxList = NIL
  584.   THEN 
  585.     (* noch kein Handler da! *)
  586.     boxList := bx;
  587.   ELSE
  588.     currBx := boxList;
  589.     WHILE (currBx # NIL) & ~found DO
  590.       IF currBx^.next = NIL
  591.       THEN 
  592.         found := TRUE
  593.       ELSE
  594.         currBx := currBx^.next;
  595.       END;
  596.     END;
  597.     IF found THEN
  598.       currBx^.next := bx;
  599.     ELSE
  600.       DISPOSE (bx);
  601.       bx := NIL;
  602.       RETURN FALSE
  603.     END;
  604.   END;
  605.   WITH bx^ DO
  606.     dontUpdate := FALSE;
  607.     next := NIL;
  608.   END;
  609.   RETURN TRUE
  610. END CreateHandler;
  611.  
  612. VAR inCreate : BOOLEAN;
  613.     globBx   : boxHandler;
  614.     
  615. PROCEDURE FindHandler ( wdw : INTEGER) : boxHandler;
  616.   VAR bx : boxHandler;
  617. BEGIN
  618.   bx := boxList;
  619.   WHILE bx # NIL DO
  620.     IF bx^.wdw = wdw THEN RETURN bx END;
  621.     bx := bx^.next;
  622.   END;
  623.   IF inCreate
  624.   THEN 
  625.     RETURN globBx
  626.   END;
  627.   RETURN NIL;
  628. END FindHandler;
  629.  
  630. PROCEDURE MakeInfoStr (msg: msgInfo; VAR str : ARRAY OF CHAR);
  631. BEGIN
  632.   WITH msg DO
  633.     Strings.Assign ("", str, v.bool);
  634.     (*
  635.     IF (refId # NIL) & (refId^[0] # '')
  636.     THEN
  637.       Strings.Append (refId^, str, v.bool);
  638.       Strings.Append ('  ', str, v.bool);
  639.     END;
  640.     *)
  641.     IF (msgType = mail) OR (msgType = comment) OR (msgType = groupcomment)
  642.     THEN
  643.       (* Gruppe hinzufgen *)
  644.       IF (group # NIL) & (group^[0] # '')
  645.       THEN
  646.         Strings.Append ('Gr.: ', str, v.bool);
  647.         Strings.Append (group^, str, v.bool);
  648.         Strings.Append ('  ', str, v.bool);
  649.       END;
  650.     ELSE
  651.       IF (receiver # NIL) & (receiver^[0] # '')
  652.       THEN
  653.         Strings.Append ('An: ', str, v.bool);
  654.         Strings.Append (receiver^, str, v.bool);
  655.         Strings.Append ('  ', str, v.bool);
  656.       END;
  657.     END;
  658.     IF (topic # NIL) & (topic^[0] # '')
  659.     THEN
  660.       Strings.Append ('Wg.: ', str, v.bool);
  661.       Strings.Append (topic^, str, v.bool);
  662.     END;
  663.     IF LENGTH (str) > 80
  664.     THEN
  665.       str[80] := 3c;
  666.       str[81] := "";
  667.     END;
  668.   END;
  669. END MakeInfoStr;
  670.  
  671. PROCEDURE MakeBoxInfo (msg : msgInfo; VAR box: boxHandler): BOOLEAN;
  672. BEGIN
  673.   IF CreateHandler(box)
  674.   THEN
  675.     WITH box^ DO
  676.       dontUpdate := FALSE;
  677.       number := msg.number;
  678.       MakeInfoStr (msg, infoStr);
  679.       (* Baum zuweisen *) 
  680.       tree := MausTauschrsc.TreeAddr^[MausTauschrsc.editctrl];
  681.       mtUtils.SetObjcStringAdr (tree, MausTauschrsc.ec_text, ADR(infoStr));
  682.       mtUtils.SetObjcString (tree, MausTauschrsc.ec_dist, msgDistribs[msg.dist]);
  683.     END;
  684.     RETURN TRUE
  685.   ELSE
  686.     RETURN FALSE
  687.   END;
  688. END MakeBoxInfo;
  689.  
  690. PROCEDURE getRect (wdw : INTEGER; wdwRect : GrafBase.Rectangle; VAR userRect, editWork : GrafBase.Rectangle);
  691.   VAR bx : boxHandler;
  692. BEGIN
  693.   bx := FindHandler (wdw);
  694.   IF bx # NIL
  695.   THEN
  696.     userRect := wdwRect;
  697.     userRect.h := bx^.tree^[0].obHeight;
  698.     bx^.r := userRect;
  699.     WITH editWork DO
  700.       x := userRect.x;
  701.       y := userRect.y + userRect.h + 1;
  702.       w := userRect.w;
  703.       h := wdwRect.h - userRect.h - 1;
  704.     END;
  705.   ELSE
  706.     userRect := GrafBase.Rectangle {wdwRect.x, wdwRect.y, 0, 0};
  707.     editWork := wdwRect;
  708.   END;
  709. END getRect;
  710.  
  711. PROCEDURE AdaptPos (tree : mtUtils.tObjcTree; r : GrafBase.Rectangle);
  712. BEGIN
  713.   WITH tree^[0] DO
  714.     obX := r.x;
  715.     obY := r.y; 
  716.     obWidth := r.w;
  717.   END;
  718. END AdaptPos;
  719.  
  720. PROCEDURE SetTree (bx : boxHandler);
  721. VAR  idx: INTEGER;
  722.       mt : MessageType;
  723. BEGIN
  724.   WITH bx^ DO
  725.     (* Koordinaten und Inhalt anpassen *)
  726.     AdaptPos (tree, r);
  727.     mtUtils.SetObjcStringAdr (tree, MausTauschrsc.ec_text, ADR(infoStr));
  728.     WITH tree^[MausTauschrsc.ec_text] DO
  729.       obWidth := r.w - obX + tree^[0].obX;  
  730.     END;
  731.     idx := FindMessage (number);
  732.     IF idx >= 0 
  733.     THEN
  734.       mt := msgArray^[idx].msgType;
  735.       mtUtils.SetState (tree, MausTauschrsc.ec_back, MagicAES.DISABLED, ~((mt=comment) OR (mt=answer) OR (mt=groupcomment) OR (mt=persanswer)));
  736.       mtUtils.SetState (tree, MausTauschrsc.ec_pop, MagicAES.DISABLED, ~((mt=mail) OR (mt=comment) OR (mt=groupcomment)));
  737.       mtUtils.SetObjcString (tree, MausTauschrsc.ec_dist, msgDistribs[msgArray^[idx].dist]);
  738.     ELSE
  739.       mtUtils.SetObjcString (tree, MausTauschrsc.ec_dist, "");
  740.     END;
  741.   END;
  742. END SetTree;
  743.  
  744. PROCEDURE drawUserBox (wdw, vdiHdl : INTEGER; wdwWork, clip : GrafBase.Rectangle; 
  745.                        textCol, backCol : INTEGER);
  746.   VAR bx : boxHandler;
  747.       tr : GrafBase.Rectangle;
  748. BEGIN
  749.   bx := FindHandler (wdw);
  750.   IF bx # NIL
  751.   THEN
  752.     WITH bx^ DO
  753.       SetTree (bx);
  754.       VDIUtil.SetTreeColor (tree, textCol, backCol);
  755.       mtUtils.ObjcArea (tree, 0, tr);
  756.       IF (clip.y + clip.h = tr.y + tr.h) & (- clip.h =  mtUtils.ObjcFrame (tree, 0))
  757.       THEN
  758.         DEC (clip.y); INC (clip.h, 2);
  759.       END;
  760.       MagicAES.ObjcDraw (tree, 0, 8, clip);
  761.     END;
  762.   END;
  763. END drawUserBox;
  764.  
  765. PROCEDURE OpenEditor (VAR msg : msgInfo; new: BOOLEAN; num : INTEGER; offset: INTEGER; forView: BOOLEAN); FORWARD;
  766.  
  767.  
  768. (*$H+*)
  769. PROCEDURE openReference (idx: INTEGER);
  770.   VAR str: CatTypes.Str1023Ptr;
  771.       gr : CARDINAL;
  772.       msg: msgInfo;
  773.       isPrivate : BOOLEAN;
  774.  
  775.   PROCEDURE getIdNumber(ptr : data.OneGroupHandle):CARDINAL;
  776.   BEGIN
  777.     RETURN data.NumberOfID(ptr, str^);
  778.   END getIdNumber;
  779.  
  780. BEGIN
  781.   msg := msgArray^[idx];  
  782.   IF ~msg.hdrRead
  783.   THEN
  784.     ReadHdrInfo (msg, TRUE);
  785.     IF ~msg.hdrRead THEN RETURN END;
  786.     (* msgArray^[idx] := msg; *)
  787.   END;
  788.   str := msg.refId;
  789.   IF LENGTH(msg.orgGroup^) = 0
  790.   THEN
  791.     gr := dataSys.private;
  792.     isPrivate := TRUE;
  793.   ELSE
  794.     isPrivate := FALSE;
  795.   END;
  796.   IF isMessage (msg.refId^) & 
  797.      (Strings.Pos ('@',msg.refId^, 0) < 0)
  798.   THEN
  799.     (* Ist ein Kommentar auf eine interne Message! *)
  800.     idx := GetMessIdx (msg.refId^);
  801.     IF idx >= 0 THEN 
  802.       OpenEditor (msgArray^[idx], FALSE, -1, 0, FALSE);
  803.     END;
  804.   ELSIF isPrivate OR GroupSelect.GroupNumber (msg.orgGroup^, gr)
  805.   THEN
  806.     v.int := grin.grinOpenWithProc(gr, getIdNumber, grin.grinNextMess, 0, grin.mOther);
  807.   END;
  808. END openReference;
  809. (*$H=*)
  810.  
  811. PROCEDURE handleObject (bx : boxHandler; idx : INTEGER; ob : INTEGER; work: GrafBase.Rectangle);
  812.   CONST maxOb = 3;
  813.   VAR pop: ADDRESS;
  814. BEGIN
  815.   pop := MausTauschrsc.TreeAddr^[MausTauschrsc.distribx];
  816.   WITH bx^ DO
  817.     IF (ob >= 0) & (ob <= maxOb) & ~mtUtils.InState (tree, ob, MagicAES.DISABLED) 
  818.      & mtUtils.InFlag (tree, ob, MagicAES.SELECTABLE)
  819.     THEN
  820.       MagicAES.ObjcChange (tree, ob, work, {MagicAES.SELECTED}, 0);
  821.       mtUtils.CalcArea (tree, ob, v.r);
  822.       WdwManager.RedrawWdw (wdw, GrafBase.Rectangle(v.r));
  823.       mtUtils.Bounce();
  824.       CASE ob OF
  825.         MausTauschrsc.ec_back : openReference (idx); |
  826.         MausTauschrsc.ec_edit : IF ~msgArray^[idx].hdrRead
  827.                                 THEN
  828.                                   ReadHdrInfo (msgArray^[idx], FALSE);
  829.                                 END;
  830.                                 IF msgArray^[idx].hdrRead  & MsgWindow.changeHdr (msgArray^[idx])
  831.                                 THEN
  832.                                   WriteMessageInfo(FALSE);
  833.                                   MakeInfoStr (msgArray^[idx], infoStr);
  834.                                   WdwManager.RedrawWdw (wdw, r);
  835.                                   MsgWindow.MsgUpdateButtons();
  836.                                   MsgWindow.MsgRedrawEntry(idx);
  837.                                   (* !!!! careForButtons (ADR(msgWindow), TRUE); *)
  838.                                   (* !!!! redrawEntry (idx); *)
  839.                                 END; |
  840.         MausTauschrsc.ec_pop  : mtUtils.CalcArea (tree, MausTauschrsc.ec_pop, v.r);
  841.                                 v.int := mtPopups.TreePopup (pop, v.r[0], v.r[1], ORD(msgArray^[idx].dist));
  842.                                 IF v.int > 0 
  843.                                 THEN
  844.                                   msgArray^[idx].dist := data.tDistribution (v.int-1);
  845.                                   WriteMessageInfo(FALSE);
  846.                                   mtUtils.SetObjcString (tree, MausTauschrsc.ec_dist, msgDistribs[msgArray^[idx].dist]);
  847.                                   WdwManager.RedrawWdw (wdw, r);
  848.                                   MsgWindow.MsgRedrawEntry(idx);
  849.                                   (* !!!! redrawEntry (idx); *)
  850.                                 END; |
  851.       ELSE
  852.       END;
  853.       MagicAES.ObjcChange (tree, ob, work, {}, 0);
  854.       mtUtils.CalcArea (tree, ob, v.r);
  855.       WdwManager.RedrawWdw (wdw, GrafBase.Rectangle(v.r));
  856.     END;
  857.   END;
  858. END handleObject;
  859.  
  860. (* Hier die Handler fr die Box mit den Kommentar-Infos *)
  861. PROCEDURE ClickInInfo (wdw, vdiHdl, mx, my : INTEGER; kState : BITSET; work : GrafBase.Rectangle);
  862.   VAR bx : boxHandler;
  863.       idx: INTEGER;
  864.       ob : INTEGER;
  865.       msg: msgInfo;
  866.  
  867. BEGIN
  868.   bx := FindHandler (wdw);
  869.   IF bx # NIL
  870.   THEN
  871.     WITH bx^ DO
  872.       idx := FindMessage (number);
  873.       IF idx >= 0
  874.       THEN
  875.         SetTree (bx);
  876.         ob := MagicAES.ObjcFind (tree, 0, 8, mx, my);
  877.         handleObject (bx, idx, ob, work);
  878.       END;
  879.     END;
  880.   END;
  881. END ClickInInfo;
  882.  
  883. PROCEDURE handleKey (wdw : INTEGER; VAR scan, c : CHAR; VAR kstate : BITSET; VAR moreChars : BOOLEAN): BOOLEAN;
  884. VAR   bx            : boxHandler;
  885.       idx           : INTEGER;
  886.       ob            : INTEGER;
  887.       work          : GrafBase.Rectangle;
  888.       withAlt       : BOOLEAN;
  889. BEGIN
  890.   bx := FindHandler (wdw);
  891.   IF bx # NIL
  892.   THEN
  893.     idx := FindMessage (bx^.number);
  894.     IF idx >= 0 THEN
  895.       moreChars := FALSE;
  896.       (* Workarea vom Fenster holen *)
  897.       WdwManager.GetWdwWork (wdw, work);
  898.       (* Jetzt habe ich den richtigen ASCII-Code *)
  899.       withAlt := MagicAES.KALT IN kstate;
  900.       IF (CatGlobal.WithAlt (kstate) & (c = 0C)) OR
  901.          (CatGlobal.WithCtrl (kstate))
  902.       THEN
  903.         (* Jetzt Tastencodes richtig holen, das AES erz„hlt da nur Mll *)
  904.         c := mtUtils.CharCode (INTEGER(ORD(scan)), kstate);
  905.       END;
  906.       CASE CAP(c) OF
  907.         'C': IF withAlt THEN 
  908.                handleObject (bx, idx, MausTauschrsc.ec_edit, work);
  909.                RETURN TRUE
  910.              END; |
  911.         'D': IF withAlt THEN 
  912.                handleObject (bx, idx, MausTauschrsc.ec_pop, work);
  913.                RETURN TRUE;
  914.              END; |
  915.         '-': IF MagicAES.KCTRL IN kstate
  916.              THEN
  917.                handleObject (bx, idx, MausTauschrsc.ec_back, work);
  918.                RETURN TRUE
  919.              END; |
  920.         'Z': IF withAlt & CatGlobal.WithShift (kstate) THEN
  921.                (* Zurckstellung um„ndern *)
  922.                IF ~msgArray^[idx].hdrRead
  923.                THEN
  924.                  ReadHdrInfo (msgArray^[idx], FALSE);
  925.                END;
  926.                IF msgArray^[idx].hdrRead
  927.                THEN
  928.                  msgArray^[idx].sendMsg := ~msgArray^[idx].sendMsg;
  929.                  WriteMessageInfo(FALSE);
  930.                  MakeInfoStr (msgArray^[idx], bx^.infoStr);
  931.                  WdwManager.RedrawWdw (wdw, bx^.r);
  932.                  MsgWindow.MsgUpdateButtons();
  933.                  MsgWindow.MsgRedrawEntry(idx);
  934.                END;               
  935.                RETURN TRUE;
  936.              END;
  937.       ELSE
  938.       END
  939.     END;
  940.   END;
  941.   RETURN MTEdit2.ChangeThisChar (wdw, scan, c, kstate, moreChars);
  942. END handleKey;
  943.  
  944. PROCEDURE userClose (wdw : INTEGER);
  945.   VAR bx, boxi : boxHandler;
  946.       idx      : INTEGER;
  947.       msgName  : CatTypes.String255;
  948.       size     : LONGCARD;
  949.       cDt, cTi : CARDINAL;
  950. BEGIN
  951.   (* boxHandler wieder aus Liste entfernen und freigeben *)
  952.   bx := FindHandler (wdw);
  953.   IF bx # NIL
  954.   THEN
  955.     (* Erstmal nachsehen, ob Text ge„ndert bei neuem Text! *)
  956.     idx := FindMessage (bx^.number);
  957.     IF (idx >= 0) & ~bx^.dontUpdate
  958.     THEN
  959.       (* Testen, ob Gr”že ver„ndert! *)
  960.       Number2Name (bx^.number, msgName);
  961.       Strings.Append (CatTypes.textExt, msgName, v.bool);
  962.       size := FileSize (MessagePath, msgName, cDt, cTi);
  963.       (* Jetzt Datum bauen *)
  964.       (* Achtung: Dieser Aufruf geht davon aus, daž der String 
  965.        * immer vorhanden und passend grož ist. Diese Annahme ist zul„ssig,
  966.        * da jede Nachricht eine E-Zeile verpažt bekommt und auch
  967.        * die L„nge der E-Zeile feststeht. Aužerdem wird beim Einlesen grožzgig
  968.        * alloziert.
  969.        *)
  970.       (* Hier gibt es einen Buserror, wenn der Pointer noch nicht 
  971.        * alloziert ist
  972.        *)
  973.       IF ~msgArray^[idx].hdrRead
  974.       THEN
  975.         ReadHdrInfo (msgArray^[idx], FALSE);
  976.       END;
  977.       IF msgArray^[idx].date # NIL
  978.       THEN
  979.         ConvertDate.MakeFreeDate (cDt, cTi, msgArray^[idx].date^);
  980.       END;
  981.       IF size # msgArray^[idx].size
  982.       THEN
  983.         msgArray^[idx].size := size;
  984.         msgArray^[idx].new := FALSE;
  985.         WriteMessageInfo(FALSE);
  986.         WriteHdrInfo (msgArray^[idx]);
  987.       ELSIF msgArray^[idx].new
  988.       THEN
  989.         (* Nachsehen, ob noch andere Fenster mit der Nachricht
  990.          * offen sind. Wenn nicht, dann Nachricht l”schen
  991.          *)
  992.         boxi := boxList;
  993.         WHILE (boxi # NIL) & ((boxi^.number # bx^.number) OR (boxi = bx)) DO
  994.           boxi := boxi^.next;
  995.         END;
  996.         IF boxi = NIL
  997.         THEN
  998.           deleteMessage (msgName, FALSE, TRUE);
  999.         END;
  1000.       ELSE
  1001.         WriteHdrInfo (msgArray^[idx]);
  1002.       END;
  1003.     END;
  1004.     IF boxList # bx
  1005.     THEN
  1006.       (* Auf Listenanfang gehen *)
  1007.       boxi := boxList; 
  1008.       (* Handler suchen in Liste *)
  1009.       WHILE (boxi # NIL) & (boxi^.next # bx) DO
  1010.         boxi := boxi^.next;
  1011.       END;
  1012.       boxi^.next := bx^.next;
  1013.     ELSE
  1014.       boxList := bx^.next;
  1015.     END;
  1016.     DISPOSE (bx);
  1017.   END;
  1018. END userClose;
  1019.  
  1020. PROCEDURE OpenEditor (VAR msg : msgInfo; new: BOOLEAN; num : INTEGER; offset: INTEGER; forView: BOOLEAN);
  1021. VAR txtName : CatTypes.String255;
  1022.     bx      : boxHandler;
  1023. BEGIN
  1024.   IF (msg.msgType # forward) & (msg.msgType # copyOther) & (msg.msgType # copyOwn)
  1025.   THEN
  1026.     (* Erstmal Headerinformationen einlesen *)
  1027.     IF ~msg.hdrRead
  1028.     THEN
  1029.       ReadHdrInfo (msg, TRUE);
  1030.       IF ~msg.hdrRead THEN RETURN END;
  1031.     END;
  1032.     (* Jetzt Editor aufrufen *)
  1033.     Number2Name (msg.number, txtName);
  1034.     Strings.Append (CatTypes.textExt, txtName, v.bool);
  1035.     Strings.Assign (txtName, OpenName, v.bool);
  1036.     
  1037.     IF MakeBoxInfo (msg, bx)
  1038.     THEN
  1039.       inCreate := TRUE;
  1040.       globBx := bx;
  1041.       IF CatEdit.OpenEditor (MessagePath, txtName, FALSE, 
  1042.                              TRUE, ADDRESS(ClickInInfo), ADDRESS(getRect), ADDRESS(drawUserBox), ADDRESS (userClose),
  1043.                              ADDRESS (handleKey), NIL, NIL, NIL, 
  1044.                              UserBLK.editRight, FALSE, UserBLK.Umbruch, num,
  1045.                              wdw)
  1046.       THEN
  1047.         bx^.wdw := wdw;
  1048.         CatEdit.SetTabsize (wdw, UserBLK.tabSize);
  1049.         ConfVars.GetConfDefBool (cAutoIndDflt, v.bool, TRUE);
  1050.         CatEdit.SetMode (wdw, CatEdit.indentMode, v.bool);
  1051.         IF new THEN CatEdit.EditSetOffset (wdw, offset); END;
  1052.         IF forView
  1053.         THEN
  1054.           CatEdit.SetMode (wdw, CatEdit.roMode, TRUE);
  1055.           CatEdit.SetMode (wdw, CatEdit.effMode, TRUE); 
  1056.         END;
  1057.       ELSE
  1058.         bx^.wdw := -1;
  1059.         inCreate := FALSE;
  1060.         userClose (-1); (* direkt wieder l”schen! *)
  1061.       END;
  1062.       inCreate := FALSE;
  1063.     ELSE
  1064.       MTE.noMemAlert ();
  1065.     END;
  1066.   END;
  1067. END OpenEditor;
  1068.  
  1069. (*=========================================================================*)
  1070.  
  1071. PROCEDURE CreateMessage (minNum : INTEGER; REF To, OrgGroup, Group, RefId, Topic, RealName : ARRAY OF CHAR; 
  1072.                          type : MessageType; copyTo : CARDINAL;
  1073.                          REF crossLine : ARRAY OF CHAR; 
  1074.                          REF oldMId : ARRAY OF CHAR;
  1075.                          oldDist    : data.tDistribution;
  1076.                          openEditor : BOOLEAN; 
  1077.                          VAR messIdx: INTEGER): BOOLEAN;
  1078.  
  1079. TYPE  lineSet = SET OF lineType;
  1080.   VAR msg : msgInfo;
  1081.       txtName : CatTypes.String255;
  1082.       txtHdl  : mtTextfiles.TEXTFILE;
  1083.       line    : lineType;
  1084.       offset,
  1085.       idx     : INTEGER;
  1086.       tmpName,
  1087.       mataGroup: CatTypes.String255;
  1088.       linesAvail: lineSet;
  1089.  
  1090.   PROCEDURE freeMsg (complain: BOOLEAN);
  1091.     VAR i : lineType;
  1092.   BEGIN
  1093.     FOR i := dateL TO rNameL DO
  1094.       IF msg.strings[i] # NIL
  1095.       THEN
  1096.         DEALLOCATE (msg.strings[i], 0)
  1097.       END;
  1098.     END;
  1099.     MTE.noMemWarn (complain);
  1100.     DEC (messages);
  1101.   END freeMsg;
  1102.   
  1103.   PROCEDURE CopyLine (VAR x : CatTypes.Str1023Ptr; REF str : ARRAY OF CHAR): BOOLEAN;
  1104.   BEGIN
  1105.     ALLOCATE (x, LENGTH (str)+2);
  1106.     IF x = NIL THEN RETURN FALSE END;
  1107.     Strings.Assign (str, x^, v.bool);
  1108.     RETURN LENGTH (str) > 0;
  1109.   END CopyLine;
  1110.   
  1111. BEGIN
  1112.   IF ~MakeNewMsgArray (FALSE, 0)
  1113.   THEN RETURN FALSE END;
  1114.   INC (messages);
  1115.   msg := msgArray^[messages-1];
  1116.   messIdx := messages-1;
  1117.   FOR line := dateL TO rNameL DO 
  1118.     msg.strings[line] := NIL;
  1119.   END;
  1120.   ALLOCATE (msg.date, 20);
  1121.   IF msg.date = NIL THEN DEC (messages); RETURN FALSE END;
  1122.   (* E-Zeile festlegen *)
  1123.   ConvertDate.MakeDate (msg.date^);
  1124.   (* Jetzt die Zeilen kopieren und merken, was ich habe *)
  1125.   linesAvail := lineSet{dateL};
  1126.   IF CopyLine (msg.refId, RefId) THEN INCL (linesAvail, refIdL); END;
  1127.   IF CopyLine (msg.receiver, To) THEN INCL (linesAvail, receiverL); END;
  1128.   IF CopyLine (msg.topic, Topic) THEN INCL (linesAvail, topicL); END;
  1129.   IF CopyLine (msg.orgGroup, OrgGroup) THEN INCL (linesAvail, orgGroupL); END;
  1130.   IF CopyLine (msg.group, Group) THEN INCL (linesAvail, groupL); END;
  1131.   IF CopyLine (msg.rId, oldMId)  THEN INCL (linesAvail, rIdL); END;
  1132.   IF CopyLine (msg.realName, RealName)  THEN INCL (linesAvail, rNameL); END;
  1133.   (* Jetzt die anderen Infos erzeugen *)
  1134.   CASE type OF 
  1135.     persanswer,
  1136.     answer,
  1137.     groupcomment, 
  1138.     copyOther,
  1139.     forward, 
  1140.     comment     : IF NOT (refIdL IN linesAvail) 
  1141.                   THEN
  1142.                     freeMsg(TRUE);
  1143.                     RETURN FALSE
  1144.                   END; 
  1145.                   IF ((type # copyOther) & (type # forward) & ~(topicL IN linesAvail))
  1146.                   THEN
  1147.                     freeMsg(TRUE);
  1148.                     RETURN FALSE
  1149.                   END; 
  1150.                   IF (type = comment) OR (type = groupcomment) OR (type = persanswer)
  1151.                   THEN
  1152.                     IF (~(groupL IN linesAvail) & (type # persanswer))
  1153.                     OR (~(orgGroupL IN linesAvail) & (type # comment))
  1154.                     THEN
  1155.                       freeMsg(TRUE);
  1156.                       RETURN FALSE
  1157.                     END; 
  1158.                   END;
  1159.                   v.bool := receiverL IN linesAvail; 
  1160.                   IF ((type = answer) OR (type = persanswer) OR 
  1161.                       (type = forward) OR (type = copyOther)) 
  1162.                   & ~ v.bool THEN
  1163.                     freeMsg(TRUE);
  1164.                     RETURN FALSE
  1165.                   END;|
  1166.     mail        : (* neue ”ffentliche Nachricht *)
  1167.                   IF NOT ((groupL IN linesAvail) & (topicL IN linesAvail))
  1168.                   THEN
  1169.                     freeMsg(TRUE);
  1170.                     RETURN FALSE 
  1171.                   END; |
  1172.     copyOwn, 
  1173.     private     : (* neue private Nachricht     *)
  1174.                   (* Kopie einer neuen privaten Nachricht *)
  1175.                   (* Abweichung: Im Stichwort wird der Kommentar fr den Empf„nger festgehalten! *)
  1176.                   IF ~(receiverL IN linesAvail) 
  1177.                   THEN
  1178.                     freeMsg(TRUE);
  1179.                     RETURN FALSE
  1180.                   END;
  1181.                   IF ((type = private) & ~(topicL IN linesAvail))
  1182.                   THEN
  1183.                     freeMsg(TRUE);
  1184.                     RETURN FALSE
  1185.                   END;
  1186.                   IF type = copyOwn
  1187.                   THEN
  1188.                     msg.refNum := copyTo;
  1189.                     idx := FindMessage (copyTo);
  1190.                     IF (idx >= 0)
  1191.                     THEN
  1192.                       IF msgArray^[idx].copyCount >= 10
  1193.                       THEN
  1194.                         MTE.info (MTE.maxCopyAlert);
  1195.                         freeMsg(FALSE);
  1196.                         RETURN FALSE;
  1197.                       END;
  1198.                       INC (msgArray^[idx].copyCount);
  1199.                       IF msg.refId # NIL THEN DEALLOCATE (msg.refId, 0); END;
  1200.                       IF NOT (CopyLine (msg.refId, RefId))
  1201.                       THEN
  1202.                         freeMsg(TRUE);
  1203.                         RETURN FALSE
  1204.                       END;
  1205.                     END; 
  1206.                   END; |
  1207.   ELSE
  1208.   END;
  1209.   (* Jetzt sind alle n”tigen Headerzeilen festgesetzt, 
  1210.    * also jetzt die Headerdatei schreiben 
  1211.    *)
  1212.   msg.number := FindNumber (minNum);
  1213.   IF msg.number = 1000
  1214.   THEN
  1215.     MTE.info (MTE.toMuchMessages);
  1216.     freeMsg(TRUE);
  1217.     RETURN FALSE
  1218.   END;
  1219.   msg.msgType := type; 
  1220.   msg.sendMsg := TRUE;
  1221.   msg.dist := data.dNone;
  1222.   msg.orgDist := oldDist;
  1223.   msg.copyCount := 0;
  1224.   msg.toDelete := FALSE;
  1225.   msg.new := TRUE;
  1226.   msg.selected := FALSE;
  1227.   msg.noRefLine := FALSE;
  1228.   msg.hdrRead := FALSE;
  1229.   msg.isSend := FALSE;
  1230.   msg.cDate := MagicDOS.Tgetdate ();
  1231.   msg.cTime := MagicDOS.Tgettime ();
  1232.   (* Reserved-Felder Nullen *)
  1233.   msg.reserved1 := 0;
  1234.   msg.reserved2 := 0;
  1235.   msgArray^[messages-1] := msg;
  1236.   (* Jetzt ist wirklich alles fertig *)
  1237.   WriteHdrInfo (msg);
  1238.   IF (type # copyOwn) & (type # copyOther) & (type # forward) & openEditor
  1239.   THEN
  1240.     (* Jetzt Textfile erzeugen *)
  1241.     Number2Name (msg.number, txtName);
  1242.     Strings.Append (CatTypes.textExt, txtName, v.bool);
  1243.     Strings.Insert (MessagePath, 0, txtName, v.bool);
  1244.     IF mtTextfiles.OpenTextfile (txtName, mtTextfiles.WRITE, 120, txtHdl)
  1245.     THEN
  1246.       IF crossLine[0] # ''
  1247.       THEN
  1248.         mtTextfiles.WriteLine (txtHdl, crossLine);
  1249.         mtTextfiles.WriteLn(txtHdl);
  1250.         mtTextfiles.WriteLn(txtHdl);
  1251.       END;
  1252.       mtTextfiles.WriteLn(txtHdl);
  1253.       offset := SHORT(mtTextfiles.Textpos (txtHdl));
  1254.       ConfVars.GetConfDefStr (cMataGroup, mataGroup, "MT.CAT");
  1255.       Strings.Upper (mataGroup);
  1256.       IF (msg.msgType = comment) OR (msg.msgType = groupcomment) OR (msg.msgType = mail)
  1257.       THEN
  1258.         Strings.Assign (msg.group^, tmpName, v.bool);
  1259.         Strings.Upper (tmpName);
  1260.         IF Strings.StrEqual (tmpName, mataGroup)
  1261.         THEN
  1262.           mtTextfiles.WriteLn (txtHdl);
  1263.           mtTextfiles.WriteLine (txtHdl, '---');
  1264.           mtTextfiles.WriteLn (txtHdl);
  1265.           mtTextfiles.WriteLine (txtHdl, 'CAT '+CatTypes.CatVersion+' vom '+CatTypes.CatDate+0C);
  1266.           mtTextfiles.WriteLn (txtHdl);
  1267.         END;
  1268.       END;
  1269.       msg.size := mtTextfiles.Textpos (txtHdl);
  1270.       msgArray^[messages-1] := msg;
  1271.       mtTextfiles.CloseTextfile (txtHdl);
  1272.     ELSE
  1273.       MTE.info (MTE.cantCreateFile);
  1274.       ClearNumber (msg.number);
  1275.       freeMsg(TRUE);
  1276.       RETURN FALSE
  1277.     END;
  1278.     (* Jetzt existieren HDR und TXT, nur noch MessageInfo wegschreiben *)
  1279.     WriteMessageInfo(TRUE);
  1280.     Protokoll.SendPathUpdate (MessagePath);
  1281.   
  1282.     OpenEditor (msg, TRUE, -1, offset, FALSE);
  1283.     
  1284.   ELSE
  1285.     WriteMessageInfo(TRUE);
  1286.   END;
  1287.   RETURN TRUE;
  1288. END CreateMessage;
  1289.  
  1290. PROCEDURE NewMessage(REF Gruppe, Wegen : ARRAY OF CHAR);
  1291. (* Eine neue Message anlegen und danach editieren *)
  1292. BEGIN
  1293.   v.bool := CreateMessage (1, '', '', Gruppe, '', Wegen, '', mail, 0, '', '', data.dNone, TRUE, v.int);
  1294. END NewMessage;
  1295.  
  1296. PROCEDURE NewKomMessage(REF fromGroup, Group, Wegen, RefId, txt, mId, To, RealName: ARRAY OF CHAR);
  1297. (* Einen Kommentar zu einer Gruppennachricht in
  1298.  * eine andere Gruppe schicken.
  1299.  *)
  1300.   VAR type : MessageType;
  1301. BEGIN
  1302.   type := groupcomment;
  1303.   v.bool := CreateMessage (1, To, fromGroup, Group, RefId, Wegen, RealName, type, 0, txt, mId, data.dNone, TRUE, v.int);
  1304. END NewKomMessage;
  1305.  
  1306. PROCEDURE NewAnsMessage(REF an, realName, fromGroup, Wegen, RefId, txt, mId : ARRAY OF CHAR);
  1307. (* Einen Kommentar zu einer Gruppennachricht an jemand 
  1308.  * pers”nlich schicken.
  1309.  *)
  1310.   VAR type : MessageType;
  1311. BEGIN
  1312.   type := persanswer;
  1313.   v.bool := CreateMessage (1, an, fromGroup, '', RefId, Wegen, realName, type, 0, txt, mId, data.dNone, TRUE, v.int);
  1314. END NewAnsMessage;
  1315.  
  1316. PROCEDURE NewPersMsg(REF Empfaenger, RealName, Wegen : ARRAY OF CHAR);
  1317. (* Eine neue pers”nliche Nachricht an jemand schicken 
  1318.  *)
  1319. BEGIN
  1320.   v.bool := CreateMessage (1, Empfaenger, '', '', '', Wegen, RealName, private, 0, '', '', data.dNone, TRUE, v.int);
  1321. END NewPersMsg;
  1322.  
  1323. CONST cRegReceiver = "Dirk Steins @ K2";
  1324.       cRegRealName = "Dirk Steins";
  1325.       cRegTopic    = "Registrierung CAT 3.0x";
  1326.  
  1327. PROCEDURE UpdateFileSize (number: INTEGER);
  1328.  VAR idx    : INTEGER;
  1329.      msg    : msgInfo;
  1330.      txtName: CatTypes.String127;
  1331. BEGIN
  1332.   idx := FindMessage (number);
  1333.   IF idx >= 0
  1334.   THEN
  1335.     msg := msgArray^[idx];
  1336.     Number2Name (msg.number, txtName);
  1337.     Strings.Append (CatTypes.textExt, txtName, v.bool);
  1338.     msg.size := FileSize (MessagePath, txtName, v.card, v.card);
  1339.     msg.new := FALSE;
  1340.     msgArray^[idx] := msg;
  1341.     WriteMessageInfo(FALSE);
  1342.   END;
  1343. END UpdateFileSize;
  1344.  
  1345. PROCEDURE NewRegMsg(VAR number: INTEGER; VAR txtName : ARRAY OF CHAR);
  1346. (* Eine neue pers”nliche Nachricht an jemand schicken 
  1347.  *)
  1348.  VAR messIdx : INTEGER;
  1349.      msg     : msgInfo;
  1350. BEGIN
  1351.   Strings.Assign ("", txtName, v.bool);
  1352.   IF CreateMessage (1, cRegReceiver, '', '', '', cRegTopic, cRegRealName, private, 0, '', '', data.dNone, FALSE, messIdx)
  1353.   THEN
  1354.     msg := msgArray^[messIdx];
  1355.     Number2Name (msg.number, txtName);
  1356.     Strings.Append (CatTypes.textExt, txtName, v.bool);
  1357.     number := msg.number;
  1358.   END;
  1359. END NewRegMsg;
  1360.  
  1361. PROCEDURE NewKom(REF Nr, Wegen, gruppe, mId, To, RealName : ARRAY OF CHAR;
  1362.                  oldDist: data.tDistribution);
  1363. (* Einen Kommentar erzeugen 
  1364.  *)
  1365. BEGIN
  1366.   v.bool := CreateMessage (1, To, gruppe, gruppe, Nr, Wegen, RealName, comment, 0, '', mId, oldDist, TRUE, v.int);
  1367. END NewKom;
  1368.  
  1369. PROCEDURE NewAnswer(REF Nr, Wegen, an, mId, RealName : ARRAY OF CHAR);
  1370. (* Eine Antwort erzeugen 
  1371.  *)
  1372. BEGIN
  1373.   v.bool := CreateMessage (1, an, '', '', Nr, Wegen, RealName, answer, 0, '', mId, data.dNone, TRUE, v.int);
  1374. END NewAnswer;
  1375.  
  1376. PROCEDURE CopyOrForwardMessage (REF Nr, To, RealName, comment : ARRAY OF CHAR; copy : BOOLEAN);
  1377.   VAR type : MessageType;
  1378. BEGIN
  1379.   IF copy THEN type := copyOther ELSE type := forward; END;
  1380.   v.bool := CreateMessage (1, To, '', '', Nr, comment, RealName, type, 0, '', '', data.dNone, FALSE, v.int);
  1381. END CopyOrForwardMessage;
  1382.  
  1383. PROCEDURE CopyOwnMessage (REF mailId, To, RealName, Comment : ARRAY OF CHAR;
  1384.                           minNum : INTEGER);
  1385.   VAR msgName   : CatTypes.String255;
  1386.       number    : INTEGER;
  1387.       pos       : CARDINAL;
  1388. BEGIN
  1389.   (* Nachsehen, ob die ersten drei Zeichen 
  1390.    * gleich msgFileName sind
  1391.    *)
  1392.   msgName := msgFileName;
  1393.   IF (mailId[0] = msgName[0]) 
  1394.    & (mailId[1] = msgName[1]) 
  1395.    & (mailId[2] = msgName[2]) 
  1396.   THEN
  1397.     (* Ok, ist wirklich eine Message *)
  1398.     pos := 3;
  1399.     number := StrConv.StrToInt (mailId, pos, v.bool);
  1400.   
  1401.     v.bool := CreateMessage (1, To, '', '', mailId, Comment, RealName, copyOwn, number, '', '', data.dNone, FALSE, v.int);
  1402.   ELSE
  1403.     (* ?????? *)
  1404.   END;
  1405. END CopyOwnMessage;
  1406.  
  1407. PROCEDURE ChangeMessage (REF internalId : ARRAY OF CHAR): BOOLEAN;
  1408. (* Wenn die Nachricht ein Kommentar oder eine Antwort ist, 
  1409.  * dann wird daraus eine entsprechende Nachricht mit Wildwestverkettung
  1410.  * erzeugt, damit die Maus die beim n„chsten Mal annimmt.
  1411.  *)
  1412.   VAR messIdx   : INTEGER;
  1413.       msgName   : CatTypes.String255;
  1414.       mess      : msgInfo;
  1415. BEGIN
  1416.   (* Nachsehen, ob die ersten drei Zeichen 
  1417.    * gleich msgFileName sind
  1418.    *)
  1419.   IF isMessage (internalId)
  1420.   THEN
  1421.     messIdx := GetMessIdx(internalId);
  1422.     IF messIdx < 0 THEN RETURN FALSE END;
  1423.     mess := msgArray^[messIdx];
  1424.     IF mess.noRefLine
  1425.     THEN
  1426.       RETURN FALSE
  1427.     END;
  1428.     mess.noRefLine := TRUE;
  1429.     IF (mess.dist = data.dNone) & (mess.orgDist # data.dNet)
  1430.     THEN 
  1431.       (* Nur in dem Fall alte Distribution bernehmen *)
  1432.       mess.dist := mess.orgDist;
  1433.     END;
  1434.     msgArray^[messIdx] := mess;
  1435.     WriteMessageInfo(FALSE);
  1436.     RETURN TRUE;
  1437.   END;
  1438.   RETURN FALSE;
  1439. END ChangeMessage;
  1440.  
  1441. PROCEDURE deleteMessage (REF internalId : ARRAY OF CHAR; killEdit: BOOLEAN;
  1442.                           changeState : BOOLEAN);
  1443.   VAR messIdx   : INTEGER;
  1444.       msgName   : CatTypes.String255;
  1445.       i         : lineType;
  1446.       j         : INTEGER;
  1447.       messNum   : INTEGER;
  1448.       parentNum,
  1449.       parentIdx : INTEGER;
  1450.       deleteParent : BOOLEAN;
  1451.       bx        : boxHandler;
  1452. BEGIN
  1453.   (* Nachsehen, ob die ersten drei Zeichen 
  1454.    * gleich msgFileName sind
  1455.    *)
  1456.   IF isMessage (internalId)
  1457.   THEN
  1458.     mtAppl.StoreMouse();
  1459.     CatGlobal.busyMouse();
  1460.     (* Ok, ist wirklich eine Message *)
  1461.     deleteParent := FALSE;
  1462.     messIdx := GetMessIdx(internalId);
  1463.     IF messIdx < 0 THEN RETURN END;
  1464.     WITH msgArray^[messIdx] DO
  1465.       toDelete := TRUE;
  1466.       IF copyCount > 0 
  1467.       THEN 
  1468.         WriteMessageInfo(TRUE);
  1469.         mtAppl.RestoreMouse();
  1470.         RETURN 
  1471.       END;
  1472.       FOR i := dateL TO rNameL DO
  1473.         IF strings[i] # NIL THEN DEALLOCATE (strings[i], 0) END;
  1474.       END;
  1475.       IF msgType = copyOwn
  1476.       THEN
  1477.         parentIdx := FindMessage (refNum);
  1478.         IF parentIdx >= 0
  1479.         THEN
  1480.           deleteParent := msgArray^[parentIdx].toDelete;
  1481.           DEC (msgArray^[parentIdx].copyCount);
  1482.           parentNum := refNum;
  1483.         END;
  1484.       END; (* IF *)
  1485.       IF (msgType = answer) & changeState 
  1486.       THEN
  1487.         (* Beantwortete Nachricht zurckstellen, falls nicht 
  1488.          * schon eine Antwort vorhanden ist
  1489.          *)
  1490.         ReadHdrInfo (msgArray^[messIdx], FALSE);
  1491.         grin.grinResetState(refId^);
  1492.       END;
  1493.     END;
  1494.     (* Nachricht aus msgArray l”schen durch runterkopieren 
  1495.      * der anderen Nachrichten
  1496.      *)
  1497.     messNum := msgArray^[messIdx].number;
  1498.     FOR j := messIdx TO messages-1 DO 
  1499.       msgArray^[j] := msgArray^[j+1];
  1500.     END;
  1501.     DEC (messages);
  1502.     Number2Name (messNum, msgName);
  1503.     Strings.Append (CatTypes.textExt, msgName, v.bool);
  1504.     v.bool := CatFiles.DeleteFile (MessagePath, msgName);
  1505.     CatGlobal.busyMouse();
  1506.     Number2Name (messNum, msgName);
  1507.     Strings.Append (CatTypes.headerExt, msgName, v.bool);
  1508.     v.bool := CatFiles.DeleteFile (MessagePath, msgName);
  1509.     CatGlobal.busyMouse();
  1510.     ClearNumber (messNum);
  1511.     WriteMessageInfo(TRUE);
  1512.     IF deleteParent THEN
  1513.       Number2Name (parentNum, msgName);
  1514.       deleteMessage (msgName, TRUE, changeState);
  1515.     END;
  1516.     IF killEdit
  1517.     THEN
  1518.       (* Nachsehen, ob zu der Nachricht ein Editor offen ist
  1519.        * Wenn ja, dann Fenster ohne Rckfrage schliežen!
  1520.        *)
  1521.       bx := boxList;
  1522.       WHILE bx # NIL DO
  1523.         IF bx^.number = messNum
  1524.         THEN
  1525.           (* Force auf TRUE sorgt dafr, das keine Nachfrage kommt *)
  1526.           v.bool := CatEdit.CloseEditor (bx^.wdw, TRUE);
  1527.           bx := boxList;
  1528.         ELSE
  1529.           bx := bx^.next;
  1530.         END;
  1531.       END;
  1532.     END;
  1533.     mtAppl.RestoreMouse();
  1534.   END;
  1535. END deleteMessage;
  1536.  
  1537. PROCEDURE DeleteMessage (REF internalId : ARRAY OF CHAR);
  1538. BEGIN
  1539.   (* Die hier wird nur von externen Modulen aufgerufen, d.h. 
  1540.    * vom Parser nach dem Einfgen. 
  1541.    * Und dann muž ich den Status nicht zurcksetzen, 
  1542.    * falls es eine Antwort ist. 
  1543.    *)
  1544.   deleteMessage (internalId, TRUE, FALSE);
  1545. END DeleteMessage;
  1546.  
  1547. PROCEDURE MsgHasCopys (REF internalId: ARRAY OF CHAR): BOOLEAN;
  1548. (* Gibt zurck, ob die Nachricht Kopien hat oder nicht. 
  1549.  * Wenn es keine private Nachricht ist, dann wird immer FALSE
  1550.  * zurckgegeben
  1551.  *)
  1552. BEGIN
  1553.   IF isMessage (internalId) & (GetMessIdx (internalId) >= 0)
  1554.   THEN
  1555.     RETURN msgArray^[GetMessIdx(internalId)].copyCount > 0;
  1556.   END;
  1557.   RETURN FALSE;
  1558. END MsgHasCopys;
  1559.  
  1560. PROCEDURE IsPrivateMessage (VAR internalId : ARRAY OF CHAR): BOOLEAN;
  1561. (* Gibt zurck, ob die Message eine private oder eine
  1562.  * ”ffentliche Nachricht ist. Der Parser muž das beim Abarbeiten
  1563.  * des Logfiles wissen, um evtl. private Nachrichten noch
  1564.  * einfgen zu k”nnen.
  1565.  *)
  1566.   VAR messIdx : INTEGER;
  1567.       msgName : CatTypes.String255;
  1568.       i       : INTEGER;
  1569.       msg     : msgInfo;
  1570.       checkCopys : BOOLEAN;
  1571. BEGIN
  1572.   checkCopys := TRUE;
  1573.   IF isMessage (internalId) & (GetMessIdx (internalId) >= 0)
  1574.   THEN
  1575.     messIdx := GetMessIdx (internalId);
  1576.     IF ~msgArray^[messIdx].toDelete
  1577.     THEN
  1578.       RETURN (msgArray^[messIdx].msgType = answer) OR
  1579.              (msgArray^[messIdx].msgType = private) OR
  1580.              (msgArray^[messIdx].msgType = persanswer)
  1581.     ELSE
  1582.       checkCopys := TRUE;
  1583.     END
  1584.   END;
  1585.   IF checkCopys
  1586.   THEN
  1587.     (* Tscha, jetzt muž ich checken, ob das eine RefId ist *)
  1588.     FOR i := 0 TO messages - 1 DO
  1589.       msg := msgArray^[i];
  1590.       IF (msg.msgType = copyOther) OR (msg.msgType = forward) OR (msg.msgType = copyOwn)
  1591.       THEN
  1592.         IF ~msg.hdrRead
  1593.         THEN
  1594.           ReadHdrInfo (msg, TRUE);
  1595.           IF ~msg.hdrRead THEN RETURN FALSE END;
  1596.           (* msgArray^[i] := msg; *)
  1597.         END;
  1598.         IF (msg.refId # NIL) & (Strings.StrEqual(msg.refId^, internalId))
  1599.         THEN
  1600.           (* Direkt mal l”schen!! *)
  1601.           (* Sp„ter mal „ndern! *)
  1602.           Number2Name (msg.number, msgName);
  1603.           Strings.Assign (msgName, internalId, v.bool);
  1604.           RETURN msg.msgType = copyOwn
  1605.         END;
  1606.       END;
  1607.     END;
  1608.   END;
  1609.   RETURN FALSE
  1610. END IsPrivateMessage;
  1611.  
  1612. PROCEDURE GetHdrInfos (REF internalId : ARRAY OF CHAR; VAR refIdPtr, ToPtr, WegenPtr, 
  1613.                        ElinePtr, longRefIdPtr : ADDRESS);
  1614. (* Gibt an den Parser die n”tigen Informationen zurck,
  1615.  * um eine pers”nliche Nachricht einzufgen
  1616.  *)
  1617.   VAR messIdx : INTEGER;
  1618.       msg     : msgInfo;
  1619. BEGIN
  1620.   IF isMessage (internalId)
  1621.   THEN
  1622.     messIdx := GetMessIdx (internalId);
  1623.     msg := msgArray^[messIdx];
  1624.     IF ~msg.hdrRead
  1625.     THEN
  1626.       ReadHdrInfo (msg, TRUE);
  1627.       (* msgArray^[messIdx] := msg; *)
  1628.     END;
  1629.     ToPtr    := msg.receiver;
  1630.     ElinePtr := msg.date;
  1631.     IF msg.msgType = copyOwn
  1632.     THEN
  1633.       IF msg.refId # NIL
  1634.       THEN
  1635.         messIdx := GetMessIdx (msg.refId^);
  1636.         msg := msgArray^[messIdx];
  1637.         IF ~msg.hdrRead
  1638.         THEN
  1639.           ReadHdrInfo (msg, TRUE);
  1640.           (* msgArray^[messIdx] := msg; *)
  1641.         END;
  1642.       END;
  1643.       refIdPtr := msg.refId;
  1644.       WegenPtr := msg.topic;
  1645.       longRefIdPtr := msg.rId;
  1646.     ELSE
  1647.       refIdPtr := msg.refId;
  1648.       WegenPtr := msg.topic;
  1649.       longRefIdPtr := msg.rId;
  1650.     END;
  1651.   END;
  1652. END GetHdrInfos;
  1653.  
  1654. PROCEDURE GetMsgFileName (VAR name : ARRAY OF CHAR);
  1655. (* Gibt an den Parser den Dateinamen zurck,
  1656.  * unter dem die Nachricht gespeichert wurde, 
  1657.  * ohne Extension
  1658.  *)
  1659.   VAR messIdx : INTEGER;
  1660. BEGIN
  1661.   IF isMessage (name)
  1662.   THEN
  1663.     messIdx := GetMessIdx (name);
  1664.     Number2Name (msgArray^[messIdx].number, name);
  1665.   END;  
  1666. END GetMsgFileName;
  1667.  
  1668. PROCEDURE LineOut (file : mtTextfiles.TEXTFILE; ch : ARRAY OF CHAR; REF str : ARRAY OF CHAR);
  1669. BEGIN
  1670.   IF ch[0] # 0C THEN mtTextfiles.WriteLine (file, ch); END;
  1671.   mtTextfiles.WriteLine (file, str);
  1672.   mtTextfiles.WriteLn (file);
  1673. END LineOut;
  1674.  
  1675. PROCEDURE SendState(REF Nr : ARRAY OF CHAR; NewState : CHAR);
  1676. VAR stateHdl : mtTextfiles.TEXTFILE; z : CARDINAL;
  1677.     stateName : CatTypes.String255;
  1678. BEGIN
  1679.   Strings.Assign (MessagePath, stateName, v.bool);
  1680.   Strings.Append (CatTypes.statusInf, stateName, v.bool);
  1681.   IF mtTextfiles.OpenTextfile (stateName, mtTextfiles.APPEND, 512, stateHdl)
  1682.   OR mtTextfiles.OpenTextfile (stateName, mtTextfiles.WRITE, 512, stateHdl)
  1683.   THEN
  1684.     LineOut (stateHdl, '#', Nr);
  1685.     LineOut (stateHdl, 'B', NewState);
  1686.     mtTextfiles.CloseTextfile (stateHdl);
  1687.     Protokoll.SendPathUpdate (MessagePath);
  1688.   ELSE
  1689.       (* ???? *)
  1690.   END;
  1691. END SendState;
  1692.  
  1693. PROCEDURE InitMessages ();
  1694. (* MsgArray allozieren und msgFile einlesen *)
  1695.  BEGIN
  1696.   IF msgArray # NIL THEN DEALLOCATE (msgArray, 0); END;
  1697.   messages := 0;
  1698.   maxMess  := 0;
  1699.   usedNumbers := msgNumberSet{};
  1700.   ReadMessageInfo();
  1701. END InitMessages;
  1702.  
  1703. PROCEDURE SortMessages();
  1704.   (* sortiert das Message-Array*)
  1705.   VAR sort  : POINTER TO ARRAY [0..$FFFF] OF msgInfoPtr;
  1706.       i     : INTEGER;
  1707.       newArray : msgArrayPtr;
  1708.  
  1709.   PROCEDURE msgComp (a1, a2 : ADDRESS) : BOOLEAN;
  1710.     VAR b1, b2 : POINTER TO msgInfoPtr;
  1711.         p1, p2 : msgInfoPtr;
  1712.   BEGIN
  1713.     b1 := a1; b2 := a2;
  1714.     p1 := msgInfoPtr (b1^);
  1715.     p2 := msgInfoPtr (b2^);
  1716.     RETURN p1^.number < p2^.number
  1717.   END msgComp;
  1718.   
  1719. BEGIN
  1720.   IF messages = 0 THEN RETURN END;
  1721.   ALLOCATE (sort, LONG(messages) * TSIZE (ADDRESS));
  1722.   IF sort = NIL THEN RETURN END;
  1723.   FOR i := 0 TO messages-1 DO
  1724.     sort^[i] := ADR(msgArray^[i]);
  1725.   END;
  1726.   v.bool := QuickSort.sortIt (0, messages-1, sort^, msgComp, TSIZE (ADDRESS), QuickSort.noBreak);
  1727.   (* Liste wieder zurckbernehmen *)
  1728.   ALLOCATE (newArray, LONG(maxMess)*TSIZE(msgInfo));
  1729.   IF newArray = NIL
  1730.   THEN 
  1731.     DEALLOCATE (sort, 0);
  1732.     RETURN
  1733.   END;
  1734.   FOR i := 0 TO messages-1 DO
  1735.     newArray^[i] := sort^[i]^;
  1736.   END;
  1737.   DEALLOCATE (msgArray, 0);
  1738.   msgArray := newArray;
  1739.   DEALLOCATE (sort, 0);
  1740.   MsgWindow.MsgSetList (msgArray, TRUE);
  1741.   (* !!!! 
  1742.   IF (msgWindow.wdw >= 0) & ~msgWindow.isHidden
  1743.   THEN
  1744.     (* Fenster ist offen *)
  1745.     msgWindow.list := msgArray;
  1746.     WdwManager.FullRedrawWdw (msgWindow.wdw);
  1747.   END;
  1748.   *)
  1749.   WriteMessageInfo(TRUE);
  1750. END SortMessages;
  1751.  
  1752. PROCEDURE UpdateEditors (msg: msgInfo);
  1753.   VAR bx     : boxHandler;
  1754. BEGIN      
  1755.   bx := boxList;
  1756.   WHILE bx # NIL DO
  1757.     IF bx^.number = msg.number
  1758.     THEN
  1759.       MakeInfoStr (msg, bx^.infoStr);
  1760.       mtUtils.SetObjcString (bx^.tree, MausTauschrsc.ec_dist, msgDistribs[msg.dist]);
  1761.       WdwManager.RedrawWdw (bx^.wdw, bx^.r);
  1762.     END;
  1763.     bx := bx^.next;
  1764.   END;
  1765. END UpdateEditors;
  1766.  
  1767. (* Ein paar Auskunftsfunktionen *)
  1768.  
  1769. PROCEDURE MsgEditorTop (wdw: INTEGER): BOOLEAN;
  1770. (* Liefert zurck, ob gerade ein Message-Editor das Topwindow ist,
  1771.  * also ein Editor, der diesem Modul bekannt ist
  1772.  *)
  1773. BEGIN
  1774.   RETURN FindHandler (wdw) # NIL;
  1775. END MsgEditorTop;
  1776.  
  1777. PROCEDURE MsgEditGetInfos (wdw: INTEGER; info: msgInfoType; VAR str: ARRAY OF CHAR);
  1778. (* Gibt die gewnschten Infos zu dem Message-Editor wdw. Wenn die Information
  1779.  * nicht vorhanden ist, dann wird ein leerer String geliefert
  1780.  *)
  1781.   VAR bx : boxHandler;
  1782.       ptr: CatTypes.Str1023Ptr;
  1783.       idx: INTEGER;
  1784. BEGIN
  1785.   Strings.Assign ('', str, v.bool);
  1786.   bx := FindHandler (wdw);
  1787.   IF bx # NIL
  1788.   THEN
  1789.     WITH bx^ DO
  1790.       idx := FindMessage (number);
  1791.       IF idx >= 0
  1792.       THEN
  1793.         IF ~msgArray^[idx].hdrRead
  1794.         THEN
  1795.           ReadHdrInfo (msgArray^[idx], FALSE);
  1796.           IF ~msgArray^[idx].hdrRead THEN RETURN END;
  1797.         END;
  1798.         ptr := msgArray^[idx].strings[lineType(ORD(info)+1)];
  1799.         IF ptr # NIL THEN Strings.Assign (ptr^, str, v.bool); END;
  1800.       END;
  1801.     END;
  1802.   END;
  1803. END MsgEditGetInfos;
  1804.  
  1805. PROCEDURE SaveEditPos (VAR max: INTEGER);
  1806. (* Sichert die Positionen der Editoren 
  1807.  * Gibt die Anzahl der gesicherten Positionen zurck
  1808.  *)
  1809. VAR   bx  : boxHandler;
  1810.       varName : ARRAY [0..127] OF CHAR;
  1811.       num : INTEGER;
  1812. BEGIN
  1813.   bx := boxList;
  1814.   max := -1;
  1815.   WHILE bx # NIL DO
  1816.     Strings.Concat (cfgEdit, StrConv.IntToStr (bx^.number, 0), varName, v.bool);
  1817.     num := CatEdit.GetEditNumber(bx^.wdw);
  1818.     IF bx^.number > max THEN max := bx^.number END;
  1819.     v.bool := ConfVars.SetConfigInt (varName, num);
  1820.     CatEdit.EditSaveWdwPos (bx^.wdw);
  1821.     bx := bx^.next;
  1822.   END;
  1823. END SaveEditPos;
  1824.  
  1825. PROCEDURE CloseAllEditors (force: BOOLEAN): BOOLEAN;
  1826. (* Schliežt alle Nachrichteneditoren
  1827.  *)
  1828. VAR   bx  : boxHandler;
  1829. BEGIN
  1830.   REPEAT
  1831.     bx := boxList;
  1832.     IF bx # NIL
  1833.     THEN
  1834.       IF ~CatEdit.CloseEditor (bx^.wdw, force)
  1835.       THEN RETURN FALSE
  1836.       END;
  1837.     END;
  1838.   UNTIL bx = NIL;
  1839.   RETURN TRUE;
  1840. END CloseAllEditors;
  1841.  
  1842. PROCEDURE ReloadEditors ();
  1843.   VAR bx : boxHandler;
  1844. BEGIN
  1845.   bx := boxList;
  1846.   WHILE bx # NIL DO
  1847.     CatEdit.EditReloadText (wdw);
  1848.     bx := bx^.next;
  1849.   END;
  1850. END ReloadEditors;
  1851.  
  1852. PROCEDURE MsgAskForSave(); 
  1853. VAR bx  : boxHandler;
  1854. BEGIN
  1855.   bx := boxList;
  1856.   REPEAT
  1857.     IF bx # NIL
  1858.     THEN
  1859.       CatEdit.AskForSave (bx^.wdw);
  1860.       bx := bx^.next;
  1861.     END;
  1862.   UNTIL bx = NIL;
  1863. END MsgAskForSave;
  1864.  
  1865. BEGIN
  1866.   msgArray := NIL;
  1867.   messages := 0;
  1868.   maxMess  := 0;
  1869. END Messages.
  1870.